延續上文關於JavaScript基本型別的內容,這篇主要講解字串(string)、布林值(boolean)、null
、undefined
和Symbol(ES6新增)。
字串就是文字。例如是'Hello World'
、'JavaScript基本功修煉'
、'12345'
等等。12345
雖然本來是數字,但放在引號''
裏就會成為了字串。
我們可以單引號''
、雙引號""
、重音符``
把字串括著:
//單引號
var singleQuote = 'JavaScript好難!'
//雙引號
var doubleQuote = "JavaScript好難!"
//重音符
var backtick = `JavaScript好難!`
注意,這些引號都不能混合使用,例如'12345"
,這樣做會報錯。
剛學JS幾星期後,我開始轉用重音符的寫法,因為它比較方便寫和閱讀,至此人生又少了點坎坷。
具體的好處:
var fruit = `Fruit:
1. apple
2. orange
3. cherry
4. banana
`
單或雙引號就不能斷行,這樣會報錯:
var fruit = "Fruit:
1. apple
2. orange
3. cherry
4. banana
"
console.log(fruit); //Uncaught SyntaxError: Invalid or unexpected token
${}
var discount = 0.7
var fries = 15
console.log(`今天薯條的售價是${fries * discount}元`);
你可能會認為這個簡單例子其實用單或雙引號也可以,就像這樣:
console.log('今天薯條的售價是' + fries * discount + '元')
這個寫法也行的。但是,如果今天的情況是要組合一大堆字串,而非單單一句,那麼我們在輸入和組合字串的時候,就要很耗時地去找出哪裏要分開,哪裏要加上引號和加號。例如我們要組合一個HTML字串時:
用${}
去寫:
//計算打折後的價錢
function discount(oldPrice){
return oldPrice * 0.7
}
var price1 = `
<h2>今天的特價貨品:</h2>
<ul>
<li>薯片:$${discount(20)},原價$20</li>
<li>漢堡:$${discount(30)},原價$30</li>
</ul>
`
用''
或""
去寫:
var price2 =
'<h2>今天的特價貨品:</h2>' + '<ul><li>薯片:$' + discount(20) + ',原價$20</li><li>漢堡:$' + discount(30) + ',原價$30</li></ul>'
雖然回傳的結果是一樣(只差在是逼在一行還是整齊地斷行),但用``
去寫,除了不用去想哪裏要下+
和''
,也可以像寫HTML一樣去寫,寫法一目了然!
使用特別文字的情況的例子:
剛才提及單或雙引號是不能斷行,但如果加上跳脫符號\n
或者\
,也是可以實現的。
var fruit1 = 'Fruit:\n1. apple\n2. orange\n3. cherry\n4. banana'
這樣寫的話,console會以斷行顯示。
var fruit3 = 'Fruit: \
1. apple \
2. orange \
3. cherry \
4. banana'
注意,\
後面不能輸入空白或其他字元。
然而這個寫法在console顯示回傳時仍是以一行顯示,並沒有斷行。所以這個寫法只是讓你在寫程式碼時,合法地在單引號或雙引號裏按enter去斷行。
其實這些字串被渲染到網頁上時,一併都是以一行顯示,所以這個微小的分別只是在查console時會碰到。
其他運用例子:
當字串裏包含了單引號,就不能用單引號去包著字串。我們可以轉用雙引號或加入\
作分隔。
console.log('Tom's car') //報錯
console.log("Tom's car")
console.log('Tom\'s car')
console.log('\u00AE') //®
console.log('\u{1F606}') // ?
布林值就是true
和false
,非常簡單。
5 == 7 //false
undefined === null //false
2 > 1 //true
通常布林值會配搭邏輯運算子||
(or)、&&
(and)、!
(not)使用。之後的文章會談到。
falsy
和truthy
兩大類。false
,它就是屬於falsy
類別,相反,true
就是屬於truthy
類別。Boolean(value)
去把值轉型為布林值。false
(falsy):0
,null
,undefined
,NaN
,""
true
(truthy):
除了以上的值都是。
以下的例子要格外注意:
Boolean('0') //true。'0'是一個字串,只要不是空字串就會回傳true
Boolean('') //false
Boolean(' ') //true。這不是一個空字串,所以回傳true
null
= 「沒有值」的值undefined
= 沒有被賦予任何值(不論有沒有宣告變數)
undefined
。但JavaScript不會自動賦予null
給變數,那必然是由你自己動手去賦予。null
和undefined
都是falsy
null
的型別是object
,但undefined
的型別是undefined
null == undefined //true
,因為它們都是falsy
。null === undefined //false
。嚴謹模式會比較兩者的型別。null
是object
,但undefined
是undefined
。ES6新增了Symbol
這個基本型別。根據MDN的解釋,它雖然也有其他用法,但最主要是用在物件裏的屬性。
A symbol value may be used as an identifier for object properties; this is the data type's primary purpose
x
和y
都是Symbol()
,它們卻不相等。const x = Symbol();
const y = Symbol();
console.log(x === y) //false
``
或""
。用Symbol時一定要寫成Symbol()
Symbol()
後面的那個()
只是用作寫下一些關於這個Symbol的描述,並沒有實際作用。例如:Symbol("person")
、Symbol("age")
。方便我們看到多個Symbol()
時,可以一眼看出()
裏的描述,幫助自己更快區分到它們,也有助於除錯。Symbol()
其中一個優勢是它並不明顯,第三方不能用某些語法去查詢到這個屬性,例如Object.keys(user)
:
const id = Symbol("id")
let user = {
name: 'Tom',
age: 23,
birthday: 'Aug 11',
id: 111,
[id]: 222
}
console.log(Object.keys(user)) //["name", "age", "birthday", "id"]
for...in
:
for (let key in user) console.log(key);
// name
// age
// birthday
// id
然而,Object.assgin()
卻可以查看到,因為這個語法原意是把所有屬性都複製起來,而Symbol()
也會被複製到。此外,Object.getOwnPropertySymbols()
也能針對找出Symbol()
屬性。
避免因為鍵值相同,使較新的屬性覆蓋掉較舊的屬性。
let user = {
name: 'Tom',
age: 23,
birthday: 'Aug 11',
id: 111
}
//覆蓋掉user的本身的id
user.id = 222;
以上這個例子可以想像成user
這個物件是來自第三方的程式碼,裏面雖然也有id
這個屬性,但我這邊也想建立一個id
的屬性作為其他用途,可是又不能蓋掉之前的id
,所以這個例子可以用Symbol()
:
let user = {
name: 'Tom',
age: 23,
birthday: 'Aug 11',
id: 111
}
//確保不會蓋掉之前的屬性
const id = Symbol("id")
user[id] = 222
更直接的寫法:
const id = Symbol("id")
let user = {
name: 'Tom',
age: 23,
birthday: 'Aug 11',
id: 111,
[id]: 222
}
注意,鍵值需要用[]
包起來,沒有用[]
的話,鍵值會變成字串型別,直接蓋掉了原本的id
。
倒過來想,如果我們想避免自己建立的屬性被第三方開發者蓋掉,我們也可以自己用Symbol()
去建立屬性。此外,使用Symbol()
也能避免第三方輕易查看到該屬性。
雖然Symbol的主要賣點是獨特的存在,但如果我們想在程式碼某個地方,再次使用同一個Symbol值,就可以用Symbol.for()
的方法。
Symbol.for()
可以把當在()
裏的字串當作是參數,例如執行Symbol.for("cat")
時,JavaScript會查看有沒有"cat"
作為參數的Symbol值,如果有,就返回這個值,如沒有,就去建立一個,把它注冊成為全域的Symbol。
以下的例子可見,id
和idAgain
是指向同一個Symbol值:
let id = Symbol.for("id");
let idAgain = Symbol.for("id");
console.log(id === idAgain) //true
如果我調用Symbol("id")
和Symbol.for("id")
各30次,Symbol("id")
會返回30個不同的Symbol值,但Symbol.for("id")
30次都是返回同一個Symbol值。
字串:
''
、""
、``
括住''
和""
包字串時不能斷行``
,連接字串時使用${}
,這樣較方便和易讀布林值:
true
和false
0
,null
,undefined
,NaN
,""
是falsy
,其餘都是truthy
Boolean()
去把值轉為布林值null
、undefined
:
null
是「沒有值」的值,undefined
是指沒有被賦予任何值null
和undefined
都是falsy
null
的型別是object
,但undefined
的型別是undefined
Symbol()
:
Symbol()
是獨一無二的Symbol()
主要用途是避免蓋掉物件裏的其他屬性Symbol()
的屬性較隱蔽,但不代表不能被查詢Symbol.for()
返回同一個symbol值JAVASCRIPT.INFO - String
JAVASCRIPT.INFO - Data Types
undefined 和 null 的差別
Symbol:
JAVASCRIPT.INFO - Symbol
ECMAScript 6 入门
The Complete Guide to JS Symbols ES6